import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse} from "axios";
import {YRequestConfig, YRequestInterceptors} from "./types";
import {REQUEST_CONSTANT} from "@/configs/constants";
import {message} from "ant-design-vue";
import {appStore} from "@/store/app/app-store";
import loginStore from "@/store/login/login-store";
import router from "@/configs/routers/routers";
import {LoginApi} from "@/apis/login-apis";
import cacheFactory, {CacheType} from "@/utils/cache/cache-factory";
// @ts-ignore
const {VITE_BASE_API_URL} = process.env

class YRequest{
    _instance: AxiosInstance
    interceptors?: YRequestInterceptors
    initLoadingState:boolean
    showLoading:boolean
    // 是否处在刷新状态
    isRefreshing?:boolean
    // 刷新token造成的等待request
    waitRequests: any[]

    constructor(config: YRequestConfig) {
        this._instance = axios.create(config);
        this.interceptors = config.interceptors
        this.showLoading = config.showLoading ?? true
        this.initLoadingState = this.showLoading
        this._instance.interceptors.request.use(this.interceptors?.requestInterceptor, this.interceptors?.requestInterceptorCatch)
        this._instance.interceptors.response.use(this.interceptors?.responseInterceptor, this.interceptors?.responseInterceptorCatch)
        this.waitRequests = []
        this.isRefreshing = false

        /**
         * 所有请求都添加都拦截器
         * request拦截器，后添加先执行
         * response拦截器， 先添加先执行
         */
        this._instance.interceptors.request.use(
            (config: YRequestConfig) => {
                if (config.showLoading == !this.initLoadingState){
                    this.showLoading = config.showLoading
                }
                if (this.showLoading){
                    // 修改 loading 状态
                    let globalStore =  appStore();
                    globalStore.changeLoadingState(true);
                }
                console.log("begin to request:", config.url)
                return config;
            },
            error => {
                // 修改 showLoading 为 初始值
                this.showLoading = this.initLoadingState
                // 修改 loading 状态
                let globalStore =  appStore();
                globalStore.changeLoadingState(false);
                return Promise.reject(error);
            }
        );
        this._instance.interceptors.response.use(
            response => {
                let globalStore =  appStore();
                globalStore.changeLoadingState(false);
                return response;
            },
            error => {
                // 修改 showLoading 为 初始值
                this.showLoading = this.initLoadingState
                // 修改 loading 状态
                let globalStore =  appStore();
                globalStore.changeLoadingState(false);
                console.log("全局res异常拦截",error.response);
                if (error.response.status == 404){
                    console.log("404错误！")
                }else{
                    message.error(error.response.data.msg)
                }
                return Promise.reject(error);
            }
        );
    }

    /**
     * 可以对某个方法设置拦截器
     */
    request<T=any>(config: YRequestConfig<T>): Promise<T> {
        return new Promise((resolve, reject) => {
            if (config.interceptors?.requestInterceptor) {
                config = config.interceptors.requestInterceptor(config);
            }
            this._instance.request<any, T, any>(config).then(response => {
                if (config.interceptors?.responseInterceptor) {
                    response = config.interceptors.responseInterceptor(response)
                }
                // 修改 showLoading 为 初始值
                this.showLoading = this.initLoadingState
                resolve(response)
            }).catch(err => {
                reject(err)
            })
        });
    }

    get<T=any>(config:YRequestConfig<T>): Promise<T> {
        return this.request<T>({...config, method: "GET"});
    }

    post<T=any>(config:YRequestConfig<T>): Promise<T> {
        return this.request<T>({...config, method: "POST"});
    }

    delete<T=any>(config:YRequestConfig<T>): Promise<T> {
        return this.request<T>({...config, method: "DELETE"});
    }

    put<T=any>(config:YRequestConfig<T>): Promise<T> {
        return this.request<T>({...config, method: "PUT"});
    }

    patch<T=any>(config:YRequestConfig<T>): Promise<T> {
        return this.request<T>({...config, method: "patch"});
    }

}

const yRequest: YRequest = new YRequest({
    baseURL: VITE_BASE_API_URL,
    timeout: 30000,
    interceptors: {
        requestInterceptor: (config:YRequestConfig): AxiosRequestConfig => {
            const needLogin = config.needLogin ?? true
            if (needLogin){
                let store = loginStore()
                // 携带token
                const token = store.tokenInfo.accessToken ?? "";
                if (token){
                    // @ts-ignore
                    config.headers[REQUEST_CONSTANT.TOKEN_HEADER] = REQUEST_CONSTANT.TOKEN_PREFIX + token;
                }
            }
            return config;
        },
        requestInterceptorCatch: (error) => {
            return Promise.reject(error);
        },
        responseInterceptorCatch: error => {
            let store = loginStore()
            const response = error.response;
            const config = response.config;
            console.log(error.config.url, response, store)
            // 如果 返回状态码为：401，并且不为刷新token的返回值
            if (response.status == 401 && !(config.url.startsWith(LoginApi.refreshToken) || config.url.startsWith(LoginApi.getToken) ) ){
                // 判断是不是在刷新状态
                if(!yRequest.isRefreshing){
                    // 判断是否有refresh token,没有的话说明需要登陆了
                    if (!store.tokenInfo?.refreshToken){
                        console.log("判断是否有refresh token,没有的话说明需要登陆了")
                        message.error("登陆身份信息失效了喔～请重新登录")
                        // 清理缓存
                        cacheFactory.instance(CacheType.LOCAL_STORAGE)?.clear();
                        store.tokenInfo = {}
                        // 页面跳转
                        redirectLogin()
                        return Promise.reject(error)
                    }
                    // 设置为正在刷新token
                    yRequest.isRefreshing = true;
                    console.log("刷新token")
                    // 刷新token
                    return store.refreshToken().then(() => {
                        config.headers[REQUEST_CONSTANT.TOKEN_HEADER] = REQUEST_CONSTANT.TOKEN_PREFIX + store.tokenInfo.accessToken;
                        yRequest.waitRequests.forEach((cb) => cb(store.tokenInfo.accessToken));
                        // 清空等待数组
                        yRequest.waitRequests = [];
                        // 重新发送
                        return yRequest._instance(config)
                    }).catch(err => {
                        console.log("catch err", err)
                    }).finally(() => {
                        console.log("finally err")
                        yRequest.waitRequests = [];
                        yRequest.isRefreshing = false;
                    })
                }else{
                    // 正在刷新token，将返回一个未执行resolve的promise
                    return new Promise((resolve) => {
                        yRequest.waitRequests.push((token:string) => {
                            config.headers[REQUEST_CONSTANT.TOKEN_HEADER] = REQUEST_CONSTANT.TOKEN_PREFIX + token;
                            resolve(yRequest._instance(config));
                        })
                    })
                }
            }else if(response.status == 401 && (config.url.startsWith(LoginApi.refreshToken))){
                message.error("登陆身份信息失效了喔～请重新登录")
                yRequest.isRefreshing = false;
                cacheFactory.instance(CacheType.LOCAL_STORAGE)?.clear();
                store.tokenInfo = {};
                yRequest.waitRequests = [];
                redirectLogin();
                return Promise.reject(error);
            }
            console.log("刷新token", error.response)
            return Promise.reject(error);

        },
        responseInterceptor: (res): AxiosResponse => {
            let globalStore =  appStore();
            const resData = res.data;
            return resData;
        }
    }
})

function redirectLogin() {
    console.log("/toLogin")
    router.push({
        path: "/login",
        // query参数会以？key=value&key=value的格式添加到url后面
        // query参数不需要配置路由规则，可以传递任何参数
        // query是固定的语法给是，用来传递?key=value查询字符串
        query:{
            // 这里使用查询参数跳转回来的路由地址传递给了登录页面
            // router.currentRoute就是当前路由对象，好比我们再组件中的this.$route
            // 当前路由对象的fullPath,就是当前路由的路径
            // redirect是我起的一个名字
            redirect: router.currentRoute.value.fullPath
        }
    })
}
export default yRequest
